﻿using System;
using System.Linq;
using System.Reflection;

using VirtualTournaments.DataAccess.EntityManagers;
using VirtualTournaments.DataAccess.EntityManagers.Attributes;
using VirtualTournaments.DataAccess.Exceptions;
using VirtualTournaments.DataAccess.Properties;

namespace VirtualTournaments.DataAccess
{
	public class DataAccessManager
	{
		private static Assembly currentImplAssembly = null;
		private static readonly object currentImplAssemblyLocker = new object();

		private static IEntityManagersFactory currentEntityManagersFactoryImpl = null;
		private static bool hasCurrentEntityManagersFactoryImpl = false;
		private static readonly object currentEntityManagersImplLocker = new object();

		public static IEntityManagersFactory EntityManagersFactory
		{
			get
			{
				if (!hasCurrentEntityManagersFactoryImpl)
				{
					lock (currentEntityManagersImplLocker)
					{
						if (!hasCurrentEntityManagersFactoryImpl)
						{
							hasCurrentEntityManagersFactoryImpl = true;

							Assembly implAssembly = GetDataAccessImplAssembly();
							Type implType = implAssembly.GetExportedTypes().FirstOrDefault(type => type.GetCustomAttributes<EntityManagersFactoryAttribute>().Length > 0);
							if (implType != null)
							{
								currentEntityManagersFactoryImpl = Activator.CreateInstance(implType) as IEntityManagersFactory;
							}
						}
					}
				}
				if (currentEntityManagersFactoryImpl == null)
					throw new EntityManagersFactoryImplementationNotFoundException();
				return currentEntityManagersFactoryImpl;
			}
		}

		private static Assembly GetDataAccessImplAssembly()
		{
			if (currentImplAssembly == null)
			{
				lock (currentImplAssemblyLocker)
				{
					if (currentImplAssembly == null)
					{
						currentImplAssembly = Assembly.Load(Settings.Default.DataAccessImplAssembly);
					}
				}
			}
			return currentImplAssembly;
		}
	}
}
